home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998 April: Mac OS SDK / Dev.CD Apr 98 SDK1.toast / Development Kits (Disc 1) / Apple Game Sprockets / RAVE SDK 1.06 GM for MacOS / Example Projects / GameScene / GSImage.c < prev    next >
Encoding:
Text File  |  1996-03-21  |  19.7 KB  |  775 lines  |  [TEXT/ALFA]

  1. // ===========================================================================
  2. //    
  3. // GSImage.c 
  4. //    
  5. //    Copyright (C) 1996 Apple Computer, Inc.  All rights reserved.
  6. //
  7. // ===========================================================================
  8.  
  9.  
  10. // ===========================================================================
  11. //    Includes
  12. // ===========================================================================
  13.  
  14. #include <stdlib.h>
  15.  
  16. #include "RAVE.h"
  17.  
  18. #include "GSImage.h"
  19. #include "GSPicture.h"
  20. #include "GSColorTable.h"
  21. #include "GSUtilities.h"
  22. #include "GSError.h"
  23.  
  24.  
  25. // ===========================================================================
  26. //    Constants
  27. // ===========================================================================
  28.  
  29. #define                     kMaxImageCount                     20
  30.  
  31.  
  32. // ===========================================================================
  33. //    Types
  34. // ===========================================================================
  35.  
  36. typedef struct TGSImage {
  37.     TQAImagePixelType         mPixelType;
  38.     TGSPicture*                mPicture;
  39.     TQAImage                mImages[kMaxImageCount];
  40.     void*                    mMipMaps;
  41.     Boolean                    mIsValidTexture;
  42.     Boolean                    mIsValidBitmap;
  43.     Boolean                    mIsValidMipMap;
  44. } TGSImage;
  45.  
  46.  
  47. // ===========================================================================
  48. //    Private Prototypes
  49. // ===========================================================================
  50.  
  51.     TGSError
  52. GSImage_MakeBlackTransparent(
  53.     TGSImage*                inImage);
  54.  
  55.     TGSError
  56. GSImage_MakeMipMap(
  57.     TGSImage*                inImage);
  58.     
  59.     long
  60. AlphaChannel(
  61.     TQAImagePixelType         inPixelType,
  62.     Byte*                     inPixelP);
  63.     
  64.     long
  65. RedChannel(
  66.     TQAImagePixelType         inPixelType,
  67.     Byte*                     inPixelP);
  68.     
  69.     long
  70. GreenChannel(
  71.     TQAImagePixelType         inPixelType,
  72.     Byte*                     inPixelP);
  73.     
  74.     long
  75. BlueChannel(
  76.     TQAImagePixelType         inPixelType,
  77.     Byte*                     inPixelP);
  78.     
  79.     void
  80. SetARGB(
  81.     TQAImagePixelType         inPixelType,
  82.     Byte*                     inPixelP, 
  83.     long                     inA, 
  84.     long                     inR, 
  85.     long                     inG, 
  86.     long                     inB);
  87.     
  88.     
  89. // ===========================================================================
  90. //    Public Routines
  91. // ===========================================================================
  92.  
  93. // ===========================================================================
  94. //    GSImage_New
  95. // ===========================================================================
  96.     TGSError
  97. GSImage_New(
  98.     TGSImage**                inImage)
  99. {
  100.     *inImage = (TGSImage*) malloc(sizeof(TGSImage));
  101.     
  102.     if (*inImage == nil) {
  103.         return kGSError_NotEnoughMemory;
  104.     }
  105.     
  106.     (**inImage).mPixelType = kQAPixel_RGB32;
  107.     (**inImage).mPicture = nil;
  108.     (**inImage).mMipMaps = nil;
  109.     (**inImage).mIsValidTexture = false;
  110.     (**inImage).mIsValidBitmap = false;
  111.     (**inImage).mIsValidMipMap = false;
  112.     
  113.     return kGSError_None;
  114. }
  115.  
  116.  
  117. // ===========================================================================
  118. //    GSImage_NewFromPicture
  119. // ===========================================================================
  120.     TGSError
  121. GSImage_NewFromPicture(
  122.     TGSImage**                inImage,
  123.     TGSPicture*             inPicture,
  124.     TQAImagePixelType         inPixelType,
  125.     Boolean                    inMakeBlackTransparent,
  126.     Boolean                    inMakeMipMap)
  127. {
  128.     TGSError                gsError;
  129.     
  130.     GSAssert_(inPicture);
  131.     
  132.     gsError = GSImage_New(inImage);
  133.     
  134.     if (gsError != kGSError_None) {
  135.         GSImage_Delete(*inImage);
  136.         return gsError;
  137.     }
  138.  
  139.     (**inImage).mPixelType = inPixelType;
  140.     
  141.         // we are now responsible for the disposal of inPicture.  we need to keep
  142.         // it around because it contains the storage for the full-size texture,
  143.         // which we'll need until this image is deleted.
  144.     (**inImage).mPicture = inPicture;
  145.  
  146.         // fill in the first image in the array, which is exactly the same as
  147.         // the inPicture
  148.     (**inImage).mImages[0].width = GSPicture_GetWidth(inPicture);
  149.     (**inImage).mImages[0].height = GSPicture_GetHeight(inPicture);
  150.     (**inImage).mImages[0].rowBytes = GSPicture_GetRowBytes(inPicture);
  151.     (**inImage).mImages[0].pixmap = GSPicture_GetPixMap(inPicture);
  152.     
  153.     if (inMakeBlackTransparent) {
  154.             // make every black pixel be transparent and every non-black one 
  155.             // be opaque
  156.         gsError = GSImage_MakeBlackTransparent(*inImage);
  157.         
  158.         if (gsError != kGSError_None) {
  159.             GSImage_Delete(*inImage);
  160.             return gsError;
  161.         }
  162.     }
  163.     
  164.         // if we've gotten here, then we at least have a valid bitmap image,
  165.         // because bitmap dimensions don't have to be powers of 2
  166.     (**inImage).mIsValidBitmap = true;
  167.     
  168.     if (GSIsPowerOf2((**inImage).mImages[0].width, nil) && 
  169.             GSIsPowerOf2((**inImage).mImages[0].height, nil)) {
  170.             // the dimensions of a texture must be a power of 2, so we have
  171.             // a valid texture
  172.         (**inImage).mIsValidTexture = true;
  173.         
  174.         if (inMakeMipMap) {
  175.                 // the caller wants mipmaps made for this texture
  176.             gsError = GSImage_MakeMipMap(*inImage);
  177.             
  178.             if (gsError != kGSError_None) {
  179.                 GSImage_Delete(*inImage);
  180.                 return gsError;
  181.             }
  182.         }
  183.     }
  184.     
  185.     return kGSError_None;
  186. }
  187.  
  188.  
  189. // ===========================================================================
  190. //    GSImage_Delete
  191. // ===========================================================================
  192.     void
  193. GSImage_Delete(
  194.     TGSImage*                inImage)
  195. {
  196.     if (inImage == nil) {
  197.         return;
  198.     }
  199.     
  200.     if (inImage->mPicture != nil) {
  201.         GSPicture_Delete(inImage->mPicture);
  202.         inImage->mPicture = nil;
  203.     }
  204.     
  205.     if (inImage->mMipMaps != nil) {
  206.         free(inImage->mMipMaps);
  207.         inImage->mMipMaps = nil;
  208.     }
  209.     
  210.     free(inImage);
  211. }
  212.  
  213.  
  214. // ===========================================================================
  215. //    GSImage_GetImages
  216. // ===========================================================================
  217.     TQAImage*
  218. GSImage_GetImages(
  219.     TGSImage*                 inImage)
  220. {
  221.     GSAssert_(inImage);
  222.     
  223.     return inImage->mImages;
  224. }
  225.  
  226.  
  227. // ===========================================================================
  228. //    GSImage_GetWidth
  229. // ===========================================================================
  230.     long
  231. GSImage_GetWidth(
  232.     TGSImage*                 inImage)
  233. {
  234.     GSAssert_(inImage);
  235.     
  236.     return inImage->mImages[0].width;
  237. }
  238.  
  239.  
  240. // ===========================================================================
  241. //    GSImage_GetHeight
  242. // ===========================================================================
  243.     long
  244. GSImage_GetHeight(
  245.     TGSImage*                 inImage)
  246. {
  247.     GSAssert_(inImage);
  248.     
  249.     return inImage->mImages[0].height;
  250. }
  251.  
  252.  
  253. // ===========================================================================
  254. //    GSImage_GetRowBytes
  255. // ===========================================================================
  256.     long
  257. GSImage_GetRowBytes(
  258.     TGSImage*                 inImage)
  259. {
  260.     GSAssert_(inImage);
  261.     
  262.     return inImage->mImages[0].rowBytes;
  263. }
  264.  
  265.  
  266. // ===========================================================================
  267. //    GSImage_GetPixelType
  268. // ===========================================================================
  269.     TQAImagePixelType
  270. GSImage_GetPixelType(
  271.     TGSImage*                 inImage)
  272. {
  273.     GSAssert_(inImage);
  274.     
  275.     return inImage->mPixelType;
  276. }
  277.  
  278.  
  279. // ===========================================================================
  280. //    GSImage_GetColorTable
  281. // ===========================================================================
  282.     TGSColorTable*
  283. GSImage_GetColorTable(
  284.     TGSImage*                 inImage)
  285. {
  286.     GSAssert_(inImage);
  287.     
  288.     return GSPicture_GetColorTable(inImage->mPicture);
  289. }
  290.  
  291.  
  292. // ===========================================================================
  293. //    GSImage_IsValidTexture
  294. // ===========================================================================
  295.     Boolean
  296. GSImage_IsValidTexture(
  297.     TGSImage*                 inImage)
  298. {
  299.     GSAssert_(inImage);
  300.     
  301.     return inImage->mIsValidTexture;
  302. }
  303.  
  304.  
  305. // ===========================================================================
  306. //    GSImage_IsValidBitmap
  307. // ===========================================================================
  308.     Boolean
  309. GSImage_IsValidBitmap(
  310.     TGSImage*                 inImage)
  311. {
  312.     GSAssert_(inImage);
  313.     
  314.     return inImage->mIsValidBitmap;
  315. }
  316.     
  317.  
  318. // ===========================================================================
  319. //    GSImage_IsValidMipMap
  320. // ===========================================================================
  321.     Boolean
  322. GSImage_IsValidMipMap(
  323.     TGSImage*                 inImage)
  324. {
  325.     GSAssert_(inImage);
  326.     
  327.     return inImage->mIsValidMipMap;
  328. }
  329.     
  330.  
  331. // ===========================================================================
  332. //    Private Routines
  333. // ===========================================================================
  334.  
  335. // ===========================================================================
  336. //    GSImage_MakeBlackTransparent
  337. // ===========================================================================
  338.     TGSError
  339. GSImage_MakeBlackTransparent(
  340.     TGSImage*                inImage)
  341. {
  342.     #define                 kARGB16mask_alpha                (1 << 15)
  343.     #define                 kARGB16mask_RGB                    ~(1 << 15)
  344.     
  345.     if (inImage->mPixelType == kQAPixel_ARGB16) {
  346.         short*                 pixMap = (short*) inImage->mImages[0].pixmap;
  347.         short*                 scanline;
  348.         long                 pixelsPerRow = inImage->mImages[0].rowBytes / 2;
  349.         long                 x, y;
  350.  
  351.         for (y = 0; y < inImage->mImages[0].height; y++) {
  352.                 // find the beginning of the next scanline
  353.             scanline = pixMap + (y * pixelsPerRow);
  354.             
  355.             for (x = 0; x < inImage->mImages[0].width; x++) {
  356.                 if ((scanline[x] & kARGB16mask_RGB) == 0) {
  357.                      // the color of this pixel is black, so make it transparent.
  358.                      // and'ing the pixel with the inverse of kARGB16mask_alpha 
  359.                      // turns off the high bit.
  360.                     scanline[x] &= ~kARGB16mask_alpha;
  361.                 } else {
  362.                      // the color of this pixel is not black, so make it opaque.
  363.                      // or'ing the pixel with kARGB16mask_alpha turns on the high bit.
  364.                     scanline[x] |= kARGB16mask_alpha;
  365.                 } 
  366.             } // endfor
  367.         } // endfor
  368.     } else if (inImage->mPixelType == kQAPixel_ARGB32) {
  369.         typedef struct Pixel32 {
  370.             unsigned char    a;        /* D31:24 */
  371.             unsigned char    r;        /* D23:16 */
  372.             unsigned char    g;        /* D15:8 */
  373.             unsigned char    b;        /* D7:0 */
  374.         } Pixel32;
  375.         
  376.         Pixel32*             scanline;
  377.         Pixel32*             pixMap = (Pixel32*) inImage->mImages[0].pixmap;
  378.         long                 pixelsPerRow = inImage->mImages[0].rowBytes / 4;
  379.         long                 x, y;
  380.         
  381.         for (y = 0; y < inImage->mImages[0].height; y++) {
  382.                 // find the beginning of the next scanline
  383.             scanline = pixMap + (y * pixelsPerRow);
  384.             
  385.             for (x = 0; x < inImage->mImages[0].width; x++) {
  386.                 if ((scanline[x].r == 0) && (scanline[x].g == 0) && (scanline[x].b == 0)) {
  387.                         // the color of this pixel is black, so make it transparent (alpha = 0)
  388.                     scanline[x].a = 0;
  389.                 } else {
  390.                         // the color of this pixel is not black, so make it opaque (alpha = 255)
  391.                     scanline[x].a = ~0;
  392.                 } 
  393.             } // endfor
  394.         } // endfor
  395.     }
  396.  
  397.     #undef                     kARGB16mask_alpha
  398.     #undef                     kARGB16mask_RGB
  399.     
  400.     return kGSError_None;
  401. }
  402.  
  403.  
  404. // ===========================================================================
  405. //    GSImage_MakeMipMap
  406. // ===========================================================================
  407.     TGSError
  408. GSImage_MakeMipMap(
  409.     TGSImage*                inImage)
  410. {
  411.     Byte*                     mipMapP;
  412.     long                    nImages, nPixels;
  413.     long                    width, height;
  414.     long                    i, x, y;
  415.     long                    halfBoxSize;
  416.     unsigned short             widthNBits, heightNBits;
  417.     short                    pixelSize = 0;
  418.     
  419.         // we don't have a valid mipmap until we get to the end of this method
  420.     inImage->mIsValidMipMap = false;
  421.     
  422.     switch (inImage->mPixelType) {
  423.         case kQAPixel_Alpha1:
  424.         case kQAPixel_CL4:
  425.         case kQAPixel_CL8:
  426.                 // we can only mipmap 16- or 32-bit images, but don't return
  427.                 // an error, since this is an expected condition
  428.             return kGSError_None;
  429.             break;
  430.             
  431.         case kQAPixel_ARGB32:
  432.         case kQAPixel_RGB32:
  433.             pixelSize = 4;
  434.             break;
  435.         
  436.         case kQAPixel_ARGB16:
  437.         case kQAPixel_RGB16:
  438.             pixelSize = 2;
  439.             break;
  440.  
  441.           default:
  442.             GSAssert_(!"Found unrecognized TQAImagePixelType in GSImage_MakeMipMap");
  443.             break;
  444.     } // endswitch
  445.  
  446.         // calculate the root-2 of of the width and height of the picture. they
  447.         // have to be a power of 2 for us to mipmap the image, so return if 
  448.         // they're not.  
  449.     if (GSIsPowerOf2((unsigned) GSImage_GetWidth(inImage), &widthNBits) == false) {
  450.         return kGSError_None;
  451.     }
  452.  
  453.     if (GSIsPowerOf2((unsigned) GSImage_GetHeight(inImage), &heightNBits) == false) {
  454.         return kGSError_None;
  455.     }
  456.  
  457.         // allocate working space for the mip map images (starting with the
  458.         // second-largest map)
  459.     nImages = ((widthNBits > heightNBits) ? widthNBits : heightNBits) + 1;
  460.     
  461.     width = 1 << (widthNBits - 1);
  462.     height = 1 << (heightNBits - 1);
  463.     
  464.         // count the number of pixels contained in all the mipmaps
  465.     for (i = nImages - 1, nPixels = 0; i > 0; i--) {
  466.         nPixels += width * height;
  467.         
  468.             // halve the width and height, making sure it's always at least 1
  469.         width >>= 1;
  470.         height >>= 1;
  471.         
  472.         if (width == 0) {
  473.             width = 1;
  474.         }
  475.         
  476.         if (height == 0) {
  477.             height = 1;
  478.         }
  479.     }
  480.  
  481.         // create an array of bytes of the proper size
  482.     inImage->mMipMaps = malloc(nPixels * pixelSize);
  483.     mipMapP = (Byte*) inImage->mMipMaps;
  484.     
  485.     if (inImage->mMipMaps == nil) {
  486.             // we don't have enough memory to create the mipmaps
  487.         return;
  488.     }
  489.     
  490.     width = 1 << (widthNBits - 1);
  491.     height = 1 << (heightNBits - 1);
  492.     
  493.         // fill in the TQAImage info.  the first image is full size, and we 
  494.         // already filled in its info in the constructor.
  495.     for (i = 1; i < nImages; i++) {
  496.         inImage->mImages[i].width = width;
  497.         inImage->mImages[i].height = height;
  498.         inImage->mImages[i].pixmap = mipMapP;
  499.         inImage->mImages[i].rowBytes = width * pixelSize;
  500.         
  501.             // go to the beginning of the next pixmap
  502.         mipMapP += width * height * pixelSize;
  503.         
  504.             // halve the width and height, making sure it's always at least 1
  505.         width >>= 1;
  506.         height >>= 1;
  507.         
  508.         if (width == 0) {
  509.             width = 1;
  510.         }
  511.         
  512.         if (height == 0) {
  513.             height = 1;
  514.         }
  515.     }
  516.  
  517.         // halfBoxSize is used to round off the box filter of four pixels.
  518.     halfBoxSize = 4 / 2;
  519.  
  520.         // Create the mipmapped images.
  521.     for (i = 1; i < nImages; i++) {
  522.         TQAImage*            prevImage;
  523.         TQAImage*            image;
  524.         long                sourceRowBytes, targetRowBytes;
  525.         Byte*                 sourceLine0;
  526.         Byte*                 sourceLine1;
  527.         Byte*                 targetLine;
  528.         
  529.         prevImage = &inImage->mImages[i - 1];
  530.         image = &inImage->mImages[i];
  531.         
  532.         sourceLine0 = (Byte*) prevImage->pixmap;
  533.         
  534.         if (prevImage->height == 1) {
  535.                 // Source image has height of 1 (widthNBits must be greater than heightNBits).
  536.                 // Make sourceLine1 duplicate sourceLine0, and set sourceRowBytes to 0 so 
  537.                 // we just keep re-reading the single source line.
  538.             sourceRowBytes = 0;
  539.             sourceLine1 = sourceLine0;
  540.         } else {
  541.                 // Normal case. sourceLine1 points one scanline above sourceLine0.
  542.             sourceRowBytes = prevImage->rowBytes;
  543.             sourceLine1 = sourceLine0 + sourceRowBytes;
  544.         }
  545.         
  546.         targetRowBytes = image->rowBytes;
  547.         targetLine = (Byte*) image->pixmap;
  548.  
  549.         for (y = image->height; y > 0; y--) {
  550.             Byte*             sourcePixel0;
  551.             Byte*             sourcePixel1;
  552.             Byte*             targetPixel;
  553.             
  554.             sourcePixel0 = sourceLine0;
  555.             sourcePixel1 = sourceLine1;
  556.             targetPixel = targetLine;
  557.             
  558.             if (prevImage->width == 1) {
  559.                     // Source image has width 1 (heightNBits must be greater than widthNBits).
  560.                     // Use a special inner loop that doesn't advance past the first pixel of
  561.                     // the source lines.
  562.                 for (x = image->width; x > 0; x--) {
  563.                     long    a, r, g, b;
  564.                     
  565.                         // Read and average two pixels from source into target.
  566.                     a = AlphaChannel(inImage->mPixelType, sourcePixel0) + 
  567.                             (halfBoxSize >> 1);
  568.                     r = RedChannel(inImage->mPixelType, sourcePixel0) + 
  569.                             (halfBoxSize >> 1);
  570.                     g = GreenChannel(inImage->mPixelType, sourcePixel0) + 
  571.                             (halfBoxSize >> 1);
  572.                     b = BlueChannel(inImage->mPixelType, sourcePixel0) + 
  573.                             (halfBoxSize >> 1);
  574.                     
  575.                     a += AlphaChannel(inImage->mPixelType, sourcePixel1);
  576.                     r += RedChannel(inImage->mPixelType, sourcePixel1);
  577.                     g += GreenChannel(inImage->mPixelType, sourcePixel1);
  578.                     b += BlueChannel(inImage->mPixelType, sourcePixel1);
  579.  
  580.                     SetARGB(inImage->mPixelType, targetPixel, a >> 1, r >> 1, g >> 1, b >> 1);
  581.  
  582.                     targetPixel += pixelSize;
  583.                 }
  584.             } else {
  585.                     // Source image has at least width 2. This is the normal case.
  586.                 for (x = image->width; x > 0; x--) {
  587.                     long    a, r, g, b;
  588.                     
  589.                         // Read and average four pixels from source into target.
  590.                     a = AlphaChannel(inImage->mPixelType, sourcePixel0) + halfBoxSize;
  591.                     r = RedChannel(inImage->mPixelType, sourcePixel0) + halfBoxSize;
  592.                     g = GreenChannel(inImage->mPixelType, sourcePixel0) + halfBoxSize;
  593.                     b = BlueChannel(inImage->mPixelType, sourcePixel0) + halfBoxSize;
  594.                     
  595.                     sourcePixel0 += pixelSize;
  596.                     
  597.                     a += AlphaChannel(inImage->mPixelType, sourcePixel1);
  598.                     r += RedChannel(inImage->mPixelType, sourcePixel1);
  599.                     g += GreenChannel(inImage->mPixelType, sourcePixel1);
  600.                     b += BlueChannel(inImage->mPixelType, sourcePixel1);
  601.                     
  602.                     sourcePixel1 += pixelSize;
  603.                     
  604.                     a += AlphaChannel(inImage->mPixelType, sourcePixel0);
  605.                     r += RedChannel(inImage->mPixelType, sourcePixel0);
  606.                     g += GreenChannel(inImage->mPixelType, sourcePixel0);
  607.                     b += BlueChannel(inImage->mPixelType, sourcePixel0);
  608.                     
  609.                     sourcePixel0 += pixelSize;
  610.                     
  611.                     a += AlphaChannel(inImage->mPixelType, sourcePixel1);
  612.                     r += RedChannel(inImage->mPixelType, sourcePixel1);
  613.                     g += GreenChannel(inImage->mPixelType, sourcePixel1);
  614.                     b += BlueChannel(inImage->mPixelType, sourcePixel1);
  615.                     
  616.                     sourcePixel1 += pixelSize;
  617.                     
  618.                     SetARGB(inImage->mPixelType, targetPixel, 
  619.                             
  620.                     a >> 2, r >> 2, g >> 2, b >> 2);
  621.                     
  622.                     targetPixel += pixelSize;
  623.                 }
  624.             }
  625.             
  626.             sourceLine0 += (sourceRowBytes << 1);
  627.             sourceLine1 += (sourceRowBytes << 1);
  628.             targetLine += targetRowBytes;
  629.         }
  630.     }
  631.     
  632.         // if we've gotten here, then we have a valid mipmap
  633.     inImage->mIsValidMipMap = true;
  634.     
  635.     return kGSError_None;
  636. }
  637.  
  638.  
  639. // ===========================================================================
  640. //    AlphaChannel
  641. // ===========================================================================
  642.     long
  643. AlphaChannel(
  644.     TQAImagePixelType         inPixelType,
  645.     Byte*                     inPixelP)
  646. {
  647.     switch (inPixelType) {
  648.         case kQAPixel_RGB32:
  649.             return 255;
  650.             break;
  651.             
  652.         case kQAPixel_RGB16:
  653.             return 1;
  654.             break;
  655.             
  656.         case kQAPixel_ARGB32:
  657.             return inPixelP[0];
  658.             break;
  659.             
  660.         case kQAPixel_ARGB16:
  661.             return (inPixelP[0] & 0x80) >> 7;
  662.             break;
  663.     } // endswitch
  664.     
  665.     return 0;
  666. }
  667.  
  668.  
  669. // ===========================================================================
  670. //    RedChannel
  671. // ===========================================================================
  672.     long
  673. RedChannel(
  674.     TQAImagePixelType         inPixelType,
  675.     Byte*                     inPixelP)
  676. {
  677.     switch (inPixelType) {
  678.         case kQAPixel_ARGB32:
  679.         case kQAPixel_RGB32:
  680.             return inPixelP[1];
  681.             break;
  682.             
  683.         case kQAPixel_ARGB16:
  684.         case kQAPixel_RGB16:
  685.             return (inPixelP[0] & 0x7C) >> 2;
  686.             break;
  687.     } // endswitch
  688.     
  689.     return 0;
  690. }
  691.  
  692.  
  693. // ===========================================================================
  694. //    GreenChannel
  695. // ===========================================================================
  696.     long
  697. GreenChannel(
  698.     TQAImagePixelType         inPixelType,
  699.     Byte*                     inPixelP)
  700. {
  701.     switch (inPixelType) {
  702.         case kQAPixel_ARGB32:
  703.         case kQAPixel_RGB32:
  704.             return inPixelP[2];
  705.             break;
  706.             
  707.         case kQAPixel_ARGB16:
  708.         case kQAPixel_RGB16:
  709.                 // the green bits straddle the two bytes
  710.             return ((inPixelP[0] & 0x03) << 3) + ((inPixelP[1] & 0xE0) >> 5);
  711.             break;
  712.     } // endswitch
  713.     
  714.     return 0;
  715. }
  716.  
  717.  
  718. // ===========================================================================
  719. //    BlueChannel
  720. // ===========================================================================
  721.     long
  722. BlueChannel(
  723.     TQAImagePixelType         inPixelType,
  724.     Byte*                     inPixelP)
  725. {
  726.     switch (inPixelType) {
  727.         case kQAPixel_ARGB32:
  728.         case kQAPixel_RGB32:
  729.             return inPixelP[3];
  730.             break;
  731.             
  732.         case kQAPixel_ARGB16:
  733.         case kQAPixel_RGB16:
  734.             return (inPixelP[1] & 0x1F);
  735.             break;
  736.     } // endswitch
  737.     
  738.     return 0;
  739. }
  740.  
  741.  
  742. // ===========================================================================
  743. //    SetARGB
  744. // ===========================================================================
  745.     void
  746. SetARGB(
  747.     TQAImagePixelType         inPixelType,
  748.     Byte*                     inPixelP, 
  749.     long                     inA, 
  750.     long                     inR, 
  751.     long                     inG, 
  752.     long                     inB)
  753. {
  754.     switch (inPixelType) {
  755.         case kQAPixel_ARGB32:
  756.         case kQAPixel_RGB32:
  757.             inPixelP[0] = (Byte) inA;
  758.             inPixelP[1] = (Byte) inR;
  759.             inPixelP[2] = (Byte) inG;
  760.             inPixelP[3] = (Byte) inB;
  761.             break;
  762.             
  763.         case kQAPixel_ARGB16:
  764.         case kQAPixel_RGB16:
  765.             inPixelP[0] = (Byte)
  766.                 ((inA & 1)    << 7) + 
  767.                 ((inR & 0x1F) << 2) + 
  768.                 ((inG & 0x18) >> 3);
  769.             inPixelP[1] = (Byte)
  770.                 ((inG & 0x07) << 5) + 
  771.                 (inB & 0x1F);
  772.             break;
  773.     } // endswitch
  774. }
  775.